home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 December / CHIPNET Aralık 1997.iso / linux / redhat / misc / src / install / doit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-11  |  16.1 KB  |  593 lines

  1. #include <errno.h>
  2. #include <fcntl.h>
  3. #include <newt.h>
  4. #include <rpmlib.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/stat.h>        /* for mkdir(2) ?!? */
  8. #include <sys/time.h>
  9. #include <sys/wait.h>
  10. #include <unistd.h>
  11.  
  12. #include "config.h"
  13. #include "doit.h"
  14. #include "install.h"
  15. #include "kbd.h"
  16. #include "log.h"
  17. #include "windows.h"
  18.  
  19. extern int testing;
  20. FILE * logFile = NULL;
  21.  
  22. static int installPackage(rpmdb db, struct installMethod * method, 
  23.               struct packageInfo * pkg, int isPreskel, 
  24.               int errfd, char * netSharedPath, int flags);
  25. static void setupXfree(struct installMethod * method, rpmdb db, 
  26.                struct pkgSet * psp, char * netSharedPath, int errfd);
  27. static void setupXmetro(struct installMethod * method, rpmdb db, 
  28.                 struct packageInfo * pkg, char * netSharedPath,
  29.             int errfd);
  30. static void setupX(struct installMethod * method, rpmdb db, 
  31.            struct pkgSet * psp, char * netSharedPath, int errfd);
  32. static void rpmerror(void);
  33.  
  34. static void swOpen(int numPackages, int sizePackages);
  35. static void swPackage(Header h);
  36. static void swPackageComplete();
  37. static void swClose(void);
  38. static void swCallback(const unsigned long amount, const unsigned long total);
  39. static void formatTime(char * buf, time_t t);
  40.  
  41. static int installCpioArchive(struct installMethod * method, char * name,
  42.                   char * logFileName) {
  43.     char * realName;
  44.     char cmd[500];
  45.     int olderrno;
  46.     int rc;
  47.     
  48.     if (method->getFile(method, name, &realName, 1)) {
  49.     if (logFile)
  50.         fprintf(logFile, "Failed to get cpio archive %s.\n", name);
  51.     return INST_ERROR;
  52.     }
  53.  
  54.     chdir("/mnt");
  55.     sprintf(cmd, "gunzip < %s | cpio -iumd --quiet 2>%s >%s", 
  56.         realName, logFileName, logFileName);
  57.  
  58.     logMessage("running: \"%s\"", cmd);
  59.  
  60.     if (testing) {
  61.     messageWindow("would run: %s", cmd);
  62.     return 0;
  63.     }
  64.  
  65.     rc = system(cmd);
  66.  
  67.     if (rc) {
  68.     olderrno = errno;
  69.     logMessage("    command failed: %s rc = %d\n", strerror(olderrno), rc);
  70.     olderrno = errno;
  71.     errorWindow("error unpacking archive: %s");
  72.  
  73.     if (method->rmFiles) unlink(realName);
  74.  
  75.     return INST_ERROR;
  76.     }
  77.  
  78.     if (method->rmFiles) unlink(realName);
  79.  
  80.     return 0;
  81. }
  82.  
  83. int doInstall(struct installMethod * method, struct component * preskel, 
  84.           struct pkgSet * psp, char * netSharedPath, char * keymap,
  85.           int upgrade) {
  86.     int i, totalNumPackages, totalSizePackages;
  87.     int flags = 0;
  88.     rpmdb db;
  89.     int errfd;
  90.     char * logFileName = "/dev/tty5";
  91.  
  92.     mkdir("/mnt/tmp", 0755);
  93.     mkdir("/mnt/var", 0755);
  94.     mkdir("/mnt/var/lib", 0755);
  95.     mkdir("/mnt/var/lib/rpm", 0755);
  96.  
  97.     if (upgrade) {
  98.     flags |= RPMINSTALL_UPGRADE | RPMINSTALL_REPLACEFILES;
  99.     logFile = fopen("/mnt/tmp/upgrade.log", "w");
  100.     } else
  101.     logFile = fopen("/mnt/tmp/install.log", "w");
  102.     if (logFile) {
  103.     setlinebuf(logFile);
  104.     if (upgrade) {
  105.         logMessage("opened /mnt/tmp/upgrade.log");
  106.     } else {
  107.         logMessage("opened /mnt/tmp/install.log");
  108.     }
  109.     } else {
  110.     if (upgrade) {
  111.         logMessage("failed to open /mnt/tmp/upgrade.log :-(");
  112.         errorWindow("Failed to open /mnt/tmp/upgrade.log. No upgrade log "
  113.                 "will be kept.");
  114.     } else {
  115.         logMessage("failed to open /mnt/tmp/install.log :-(");
  116.         errorWindow("Failed to open /mnt/tmp/install.log. No install log "
  117.                 "will be kept.");
  118.     }
  119.     }
  120.  
  121.     errfd = open(logFileName, O_APPEND | O_CREAT, 0644);
  122.     if (errfd < 0) {
  123.     logMessage("failed to open /dev/tty5!");
  124.     logFileName = "/tmp/exec.log";
  125.     errfd = open(logFileName, O_APPEND | O_CREAT, 0644);
  126.     if (errfd < 0) {
  127.         logMessage("failed to open %s: %s!\n", logFileName, 
  128.             strerror(errno));
  129.         errfd = 2;
  130.     }
  131.     }
  132.  
  133.     rpmErrorSetCallback(rpmerror);
  134.  
  135.     logMessage("reading /usr/lib/rpmrc");
  136.     rpmReadConfigFiles(NULL, NULL, NULL, 0);
  137.     logMessage("\tdone");
  138.  
  139.     if (testing) {
  140.     messageWindow("Status", "Packages would be installed now");
  141.     return 0;
  142.     }
  143.  
  144.     if (rpmdbOpen("/mnt", &db, O_RDWR | O_CREAT, 0644)) {
  145.     errorWindow("Fatal error opening RPM database");
  146.     return INST_ERROR;
  147.     }
  148.     logMessage("opened rpm database");
  149.  
  150.     /* It's safer to *always* install the base system */
  151.     winStatus(45, 3, "Base system", "Installing base system...");
  152.  
  153.     if (installCpioArchive(method, "skeleton.cgz", logFileName))
  154.     return INST_ERROR;
  155.  
  156.     newtPopWindow();
  157.  
  158.     logMessage("installing initial packages (%d of them)", 
  159.         preskel->ps.numPackages);
  160.  
  161.     totalNumPackages = 0, totalSizePackages = 0;
  162.     for (i = 0; i < psp->numPackages; i++) {
  163.     if (psp->packages[i]->selected) {
  164.         totalSizePackages += psp->packages[i]->size;
  165.         totalNumPackages++;
  166.     }
  167.     }
  168.  
  169.     swOpen(totalNumPackages, totalSizePackages);
  170.  
  171.     for (i = 0; i < preskel->ps.numPackages; i++) {
  172.     if (!preskel->ps.packages[i]->selected) continue;
  173.     logMessage("    installing %s", preskel->ps.packages[i]->name);
  174.     installPackage(db, method, preskel->ps.packages[i], 1, errfd, 
  175.             netSharedPath, flags);
  176.     preskel->ps.packages[i]->selected = 0;    /* don't install it later */
  177.     }
  178.  
  179.     #ifndef __sparc__
  180.     mkdir("/mnt/etc/sysconfig", 0755);
  181.     writeKbdConfig("/mnt/etc/sysconfig", keymap);
  182.     #endif
  183.  
  184.     logMessage("installing packages");
  185.     for (i = 0; i < psp->numPackages; i++) {
  186.     if (!psp->packages[i]->selected) continue;
  187.     installPackage(db, method, psp->packages[i], 0, errfd, 
  188.             netSharedPath, flags);
  189.     }
  190.     swClose();
  191.  
  192.     if (!upgrade) {
  193.     mouseConfig();
  194.         setupX(method, db, psp, netSharedPath, errfd);
  195.     }
  196.  
  197.     rpmdbClose(db);
  198.     close(errfd);
  199.  
  200.     if (logFile) fclose(logFile);
  201.  
  202.     logMessage("rpm database closed");
  203.  
  204.     return 0;
  205. }
  206.  
  207. static int installPackage(rpmdb db, struct installMethod * method, 
  208.               struct packageInfo * pkg, int isPreskel, 
  209.               int errfd, char * netSharedPath, int flags) {
  210.     int fd, olderr;
  211.     char * realName;
  212.     int olderrno, rc;
  213.  
  214.     if (flags & RPMINSTALL_UPGRADE) {
  215.     if (logFile)
  216.         fprintf(logFile, "Upgrading %s.\n", pkg->name);
  217.     } else {
  218.     if (logFile)
  219.         fprintf(logFile, "Installing %s.\n", pkg->name);
  220.     }
  221.  
  222.     swPackage(pkg->h);
  223.  
  224.     if (method->getFile(method, pkg->data, &realName, isPreskel)) {
  225.     logMessage("getFile method failed for %s", pkg->data);
  226.     if (logFile)
  227.         fprintf(logFile, "Failed to get file for package %s.\n", pkg->name);
  228.     swPackageComplete();
  229.     return 1;
  230.     }
  231.  
  232.     fd = open(realName, O_RDONLY);
  233.     if (fd < 0) {
  234.     olderrno = errno;
  235.     logMessage("cannot open RPM file %s: %s", pkg->data,
  236.             strerror(olderrno));
  237.     messageWindow("Error", "Error installing package: cannot open RPM file "
  238.             "for %s: %s", pkg->data, strerror(errno));
  239.     if (logFile)
  240.         fprintf(logFile, "\tcannot open RPM file %s: %s\n", 
  241.             (char *) pkg->data, strerror(olderrno));
  242.  
  243.     swPackageComplete();
  244.  
  245.     return 1;
  246.     }
  247.  
  248.     olderr = dup(2);
  249.     dup2(errfd, 2);
  250.     rc = rpmInstallPackage("/mnt", db, fd, NULL, 
  251.         flags | RPMINSTALL_REPLACEPKG | RPMINSTALL_REPLACEFILES, 
  252.             swCallback, NULL, netSharedPath);
  253.     dup2(olderr, 2);
  254.     close(olderr);
  255.  
  256.     if (rc) {
  257.     olderrno = errno;
  258.     logMessage("Error installing package: package install of "
  259.             "%s failed: %s", pkg->name, rpmErrorString());
  260.     messageWindow("Error", "RPM install of %s failed: %s", pkg->name,
  261.             rpmErrorString());
  262.     if (logFile)
  263.         fprintf(logFile, "\tcannot open RPM file %s: %s\n", 
  264.             (char *) pkg->data, strerror(olderrno));
  265.     } 
  266.  
  267.     close(fd);
  268.     swPackageComplete();
  269.  
  270.     if (method->rmFiles) unlink(realName);
  271.  
  272.     return 0;
  273. }
  274.  
  275. static void setupX(struct installMethod * method, rpmdb db, 
  276.            struct pkgSet * psp, char * netSharedPath, int errfd) {
  277.     int hasMetro = 0, i;
  278.     newtComponent text, yes, no, form, answer;
  279.     struct packageInfo * metroPackage = NULL;
  280.  
  281.     /* This is a cheap trick to see if our X component was installed */
  282.     if (access("/mnt/usr/X11R6/bin/Xconfigurator", X_OK)) {
  283.     logMessage("/mnt/usr/X11R6/bin/Xconfigurator cannot be run");
  284.     return;
  285.     }
  286.  
  287.     logMessage("looking for metrox");
  288.     for (i = 0; i < psp->numPackages; i++) {
  289.     if (!strcmp(psp->packages[i]->name, "metroess")) {
  290.         logMessage("\tfound metrolink!");
  291.         metroPackage = psp->packages[i];
  292.         hasMetro = 1;
  293.         break;
  294.     }
  295.     }
  296.  
  297.     if (!hasMetro)
  298.     return setupXfree(method, db, psp, netSharedPath, errfd);
  299.  
  300.     newtOpenWindow(10, 4, 60, 16, "Metro-X");
  301.  
  302.     text = newtTextbox(1, 1, 58, 9, NEWT_TEXTBOX_WRAP);
  303.     newtTextboxSetText(text, 
  304.     "This copy of Red Hat Linux includes MetroX from MetroLink.\n\n" 
  305.     "MetroX is LICENSED SOFTWARE.  Your purchase of Red Hat Linux "
  306.     "entitles you to one (1) user license for this software.  You "
  307.     "may not install and run MetroX on more than one computer "
  308.     "without purchasing additional licenses, which are available "
  309.     "from Red Hat Software (800) 454-5502. Would you like to install "
  310.     "MetroX on your computer?");
  311.     yes = newtButton(13, 12, "Yes");
  312.     no = newtButton(36, 12, "No");
  313.     
  314.     form = newtForm(NULL, NULL, 0);
  315.     newtFormAddComponents(form, text, yes, no, NULL);
  316.  
  317.     newtRunForm(form);
  318.     answer = newtFormGetCurrent(form);
  319.  
  320.     newtFormDestroy(form);
  321.     newtPopWindow();
  322.  
  323.     if (answer == yes) {
  324.     setupXmetro(method, db, metroPackage, netSharedPath, errfd);
  325.     } else {
  326.     setupXfree(method, db, psp, netSharedPath, errfd);
  327.     }
  328. }
  329.  
  330. static void setupXmetro(struct installMethod * method, rpmdb db, 
  331.                 struct packageInfo * pkg, char * netSharedPath,
  332.             int errfd) {
  333.     int childpid;
  334.     int status;
  335.  
  336.     swOpen(1, pkg->size);
  337.     installPackage(db, method, pkg, 0, errfd, netSharedPath, 0);
  338.     swClose();
  339.  
  340.     symlink("../../usr/X11R6/bin/Xmetro", "/mnt/etc/X11/X");
  341.  
  342.     newtSuspend();
  343.     if (!(childpid = fork())) {
  344.     chroot("/mnt");
  345.     putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin");
  346.     chdir("/");
  347.     execl("/usr/X11R6/bin/configX", "/usr/X11R6/bin/configX", NULL);
  348.     }
  349.  
  350.     waitpid(childpid, &status, 0);
  351.  
  352.     newtResume();
  353. }
  354.  
  355. static void setupXfree(struct installMethod * method, rpmdb db, 
  356.                struct pkgSet * psp, char * netSharedPath, int errfd) {
  357.     int childpid;
  358.     int status;
  359.     int fd, i;
  360.     char buf[200], * chptr;
  361.     char server[50];
  362.  
  363.     newtSuspend();
  364.     if (!(childpid = fork())) {
  365.     chroot("/mnt");
  366.     putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin");
  367.     chdir("/");
  368.     execl("/usr/X11R6/bin/Xconfigurator", "/usr/X11R6/bin/Xconfigurator",
  369.           "--pick", NULL);
  370.     }
  371.  
  372.     waitpid(childpid, &status, 0);
  373.  
  374.     newtResume();
  375.  
  376.     if ((fd = open("/mnt/tmp/SERVER", O_RDONLY)) < 0) {
  377.     logMessage("failed to open /mnt/tmp/SERVER: %s", strerror(errno));
  378.     return;
  379.     }
  380.  
  381.     buf[0] = '\0';
  382.     read(fd, buf, sizeof(buf));
  383.     close(fd);
  384.     chptr = buf;
  385.     while (chptr < (buf + sizeof(buf) - 1) && *chptr && *chptr != ' ')
  386.     chptr++;
  387.  
  388.     if (chptr >= (buf + sizeof(buf) - 1) || *chptr != ' ') {
  389.     logMessage("couldn't find ' ' in /mnt/tmp/SERVER");
  390.     return;
  391.     }
  392.  
  393.     *chptr = '\0';
  394.     strcpy(server, "XFree86-");
  395.     strcat(server, buf);
  396.  
  397.     logMessage("I will install the %s package", server);
  398.  
  399.     for (i = 0; i < psp->numPackages; i++) {
  400.     if (!strcmp(psp->packages[i]->name, server)) {
  401.         logMessage("\tfound package: %s", psp->packages[i]->name);
  402.         swOpen(1, psp->packages[i]->size);
  403.         installPackage(db, method, psp->packages[i], 0, errfd, 
  404.                 netSharedPath, 0);
  405.         swClose();
  406.         break;
  407.     }
  408.     }
  409.  
  410.     newtSuspend();
  411.     if (!(childpid = fork())) {
  412.     chroot("/mnt");
  413.     chdir("/");
  414.     execl("/usr/X11R6/bin/Xconfigurator", "/usr/X11R6/bin/Xconfigurator",
  415.           "--continue", NULL);
  416.     }
  417.  
  418.     waitpid(childpid, &status, 0);
  419.  
  420.     newtResume();
  421. }
  422.  
  423. static void rpmerror(void) {
  424.     int code;
  425.  
  426.     code = rpmErrorCode();
  427.     if (code != RPMERR_UNLINK && code != RPMERR_RMDIR) {
  428.     if (logFile)
  429.         fprintf(logFile, "%s\n", rpmErrorString());
  430.     else
  431.         logMessage(rpmErrorString());
  432.     }
  433. }
  434.  
  435. static struct statusWindowInfo {
  436.     newtComponent form, packageLabel, sizeLabel, summaryText;
  437.     newtComponent pkgScale, globalScale;
  438.     newtComponent pkgDoneLabel, pkgRemainsLabel;
  439.     newtComponent sizeDoneLabel, sizeRemainsLabel;
  440.     newtComponent timeDoneLabel, timeRemainsLabel, timeTotalLabel;
  441.     int numPackages, packagesDone;
  442.     unsigned int sizePackages, sizeDone;
  443.     int thisPackageSize;
  444.     time_t timeStarted;
  445. } si;
  446.  
  447. static void swOpen(int numPackages, int sizePackages) {
  448.     char buf[50];
  449.  
  450.     newtOpenWindow(10, 4, 60, 15, "Install Status");
  451.  
  452.     si.form = newtForm(NULL, NULL, 0);
  453.     newtFormAddComponent(si.form, newtLabel(1, 1, "Package:"));
  454.     newtFormAddComponent(si.form, newtLabel(1, 2, "Size   :"));
  455.     newtFormAddComponent(si.form, newtLabel(1, 3, "Summary:"));
  456.  
  457.     si.packageLabel = newtLabel(13, 1, "");
  458.     si.sizeLabel    = newtLabel(13, 2, "");
  459.     si.summaryText  = newtTextbox(13, 3, 45, 2, NEWT_TEXTBOX_WRAP);
  460.  
  461.     si.pkgScale = newtScale(3, 6, 54, 100);
  462.  
  463.     newtFormAddComponent(si.form, 
  464.     newtLabel(1, 8, "             Packages       Bytes           Time"));
  465.     /*         12345678901234567890123456789012345678901234567
  466.                   1         2         3         4 */
  467.     newtFormAddComponent(si.form, newtLabel(1, 9,  "Total     :"));
  468.     newtFormAddComponent(si.form, newtLabel(1, 10, "Completed :"));
  469.     newtFormAddComponent(si.form, newtLabel(1, 11, "Remaining :"));
  470.  
  471.     si.numPackages = numPackages;
  472.     si.sizePackages = sizePackages;
  473.     si.packagesDone = 0;
  474.     si.sizeDone = 0;
  475.     si.timeStarted = time(NULL);
  476.  
  477.     sprintf(buf, "%8d", numPackages);
  478.     newtFormAddComponent(si.form, newtLabel(14, 9, buf));
  479.     si.pkgDoneLabel = newtLabel(14, 10, "");
  480.     si.pkgRemainsLabel = newtLabel(14, 11, "");
  481.  
  482.     sprintf(buf, "%4uM", sizePackages / (1024 * 1024));
  483.     newtFormAddComponent(si.form, newtLabel(29, 9, buf));
  484.     si.sizeDoneLabel = newtLabel(29, 10, "");
  485.     si.sizeRemainsLabel = newtLabel(29, 11, "");
  486.  
  487.     si.timeTotalLabel = newtLabel(42, 9, "");
  488.     si.timeDoneLabel = newtLabel(42, 10, "");
  489.     si.timeRemainsLabel = newtLabel(42, 11, "");
  490.  
  491.     si.globalScale = newtScale(1, 13, 58, sizePackages);
  492.  
  493.     newtFormAddComponents(si.form, si.packageLabel, si.sizeLabel, 
  494.               si.summaryText, si.pkgScale, si.globalScale, 
  495.               si.pkgDoneLabel, si.pkgRemainsLabel, 
  496.               si.sizeDoneLabel, si.sizeRemainsLabel, 
  497.               si.timeDoneLabel, si.timeRemainsLabel,
  498.               si.timeTotalLabel, NULL);
  499. }
  500.  
  501. static void swPackage(Header h) {
  502.     char * name, * version, * release, * summary;
  503.     char buf[50];
  504.     uint_32 * size;
  505.  
  506.     headerGetEntry(h, RPMTAG_NAME, NULL, (void *) &name, NULL);
  507.     headerGetEntry(h, RPMTAG_VERSION, NULL, (void *) &version, NULL);
  508.     headerGetEntry(h, RPMTAG_RELEASE, NULL, (void *) &release, NULL);
  509.     headerGetEntry(h, RPMTAG_SIZE, NULL, (void *) &size, NULL);
  510.  
  511.     if (!headerGetEntry(h, RPMTAG_SUMMARY, NULL, (void *) &summary, NULL))
  512.     summary = "(no summary)";
  513.  
  514.     sprintf(buf, "%s-%s-%s", name, version, release);
  515.     newtLabelSetText(si.packageLabel, buf);
  516.  
  517.     sprintf(buf, "%dk", (*size) / 1024);
  518.     newtLabelSetText(si.sizeLabel, buf);
  519.  
  520.     newtTextboxSetText(si.summaryText, summary);
  521.  
  522.     si.thisPackageSize = *size;
  523.  
  524.     newtScaleSet(si.pkgScale, 0);
  525.  
  526.     newtDrawForm(si.form);
  527.     newtRefresh();
  528. }
  529.  
  530. static void swPackageComplete(void) {
  531.     char buf[50];
  532.     time_t now, finishTime, elapsedTime, remainingTime;
  533.  
  534.     si.packagesDone++;
  535.     si.sizeDone += si.thisPackageSize;
  536.  
  537.     sprintf(buf, "%8d", si.packagesDone);
  538.     newtLabelSetText(si.pkgDoneLabel, buf);
  539.  
  540.     sprintf(buf, "%8d", si.numPackages - si.packagesDone);
  541.     newtLabelSetText(si.pkgRemainsLabel, buf);
  542.  
  543.     sprintf(buf, "%4dM", si.sizeDone / (1024 * 1024));
  544.     newtLabelSetText(si.sizeDoneLabel, buf);
  545.  
  546.     sprintf(buf, "%4dM", (si.sizePackages - si.sizeDone) / (1024 * 1024));
  547.     newtLabelSetText(si.sizeRemainsLabel, buf);
  548.  
  549.     now = time(NULL);
  550.     elapsedTime = now - si.timeStarted;
  551.     formatTime(buf, elapsedTime);
  552.     newtLabelSetText(si.timeDoneLabel, buf);
  553.  
  554.     finishTime = (((float) si.sizePackages) / si.sizeDone) * elapsedTime;
  555.     formatTime(buf, finishTime);
  556.     newtLabelSetText(si.timeTotalLabel, buf);
  557.     
  558.     remainingTime = finishTime - elapsedTime;
  559.     formatTime(buf, remainingTime);
  560.     newtLabelSetText(si.timeRemainsLabel, buf);
  561.  
  562.     newtScaleSet(si.globalScale, si.sizeDone);
  563.  
  564.     newtRefresh();
  565. }
  566.  
  567. static void swCallback(const unsigned long amount, const unsigned long total) {
  568.     if (total == 0)
  569.     newtScaleSet(si.pkgScale, 100);
  570.     else
  571.     newtScaleSet(si.pkgScale, (amount * 100) / total);
  572.  
  573.     newtRefresh();
  574. }
  575.  
  576. static void swClose(void) {
  577.     newtPopWindow();
  578. }
  579.  
  580. static void formatTime(char * buf, time_t t) {
  581.     int hours, minutes, secs;
  582.  
  583.     hours = t / 60 / 60;
  584.     t %= (60 * 60);
  585.  
  586.     minutes = t / 60;
  587.     t %= 60;
  588.  
  589.     secs = t;
  590.  
  591.     sprintf(buf, "%01d:%02d.%02d", hours, minutes, secs);
  592. }
  593.